using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using System;
using UnityEngine.Events;
using Game.UI;
using Game.Global.Helper;
using System.Collections.Generic;

/// <summary>
/// 自定义的触摸屏操作：
/// 给定移动范围、在移动范围内操作摇杆图片，并更新CrossPlatformInput的轴向值
/// (如果不Attach到物体上，则只有鼠标输入可获取，如果需要虚拟Pad，请Attach到虚拟摇杆触点子物体中)
/// </summary>
public class MyInput : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler
{
    //--------------------------------------------------------------------------------------------------------------
    //------------------------------------------------公用静态函数------------------------------------------------
    //--------------------------------------------------------------------------------------------------------------
    #region 静态部分

    #region --虚拟摇杆以及按钮事件

    /// <summary>
    /// 不分左右Shift:是否按着shift
    /// </summary>
    public static bool IsShiftHold()
    {
        return Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
    }

    /// <summary>
    /// 不分左右:是否按着Alt
    /// </summary>
    public static bool IsAltHold()
    {
        return Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt);
    }

    /// <summary>
    /// 不分左右:是否按着Clt
    /// </summary>
    public static bool IsCltHold()
    {
        return Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
    }


    public static float GetVerticalAxis()
    {
#if UNITY_EDITOR || UNITY_STANDALONE
        //PC 下，则尝试尝试键盘的咯
        if (!isAnyVirtualAxisDown)
        {
            //尝试获取键盘的：
            axisVector.y = Input.GetAxis("Vertical");
        }
#endif
        return axisVector.y;
    }
    public static float GetHorizontalAxis()
    {
#if UNITY_EDITOR || UNITY_STANDALONE
        //PC 下，还可尝试尝试键盘输入
        if (!isAnyVirtualAxisDown)
        {
            //尝试获取键盘的：
            axisVector.x = Input.GetAxis("Horizontal");
        }
#endif
        return axisVector.x;
    }

    /// <summary>
    /// 是否有移动的按键按下（WASD或者摇杆）
    /// </summary>
    /// <returns></returns>
    public static bool IsAnyAxisChange()
    {
#if UNITY_EDITOR|| UNITY_STANDALONE
        if (Math.Abs(GetHorizontalAxis()) > 0.1f || Math.Abs(GetVerticalAxis()) > 0.1f)
        {
            return true;
        }
#endif
        //探测是否按下了虚拟摇杆
        return isAnyVirtualAxisDown;
    }

    /// <summary>
    /// 是否有任何接触或者按键
    /// </summary>
    /// <returns></returns>
    public static bool IsAnyTouch()
    {
#if UNITY_EDITOR|| UNITY_STANDALONE
        if (Input.anyKey)
        {
            return true;
        }
#endif
        return Input.touchCount > 0;
    }

    static Vector3[] m_lastPCMousePoses = new Vector3[3];
    [System.Obsolete("弃用此方法，应该不需要如此之多")]
    //PC端的中键移动
    /// <summary>
    /// PC：获得拖动移动范围
    /// </summary>
    /// <param name="mouseBt">哪个按键</param>
    /// <returns></returns>
    public static Vector3 GetMouseDelta(int mouseBt = 2)
    {
        if (Input.GetMouseButtonDown(mouseBt))
        {
            m_lastPCMousePoses[mouseBt] = mousePosition;
            return Vector3.zero;
        }
        else if (Input.GetMouseButton(mouseBt))
        {
            Vector2 delta = m_lastPCMousePoses[mouseBt] - mousePosition;
            m_lastPCMousePoses[mouseBt] = mousePosition;
            return delta;
        }
        else
        {
            return Vector3.zero;
        }
    }

    /// <summary>
    /// 获得方向上的移动（如WASD、或者虚拟摇杆）
    /// </summary>
    public static Vector2 GetMoveAxis()
    {
        //PC下：
#if UNITY_EDITOR|| UNITY_STANDALONE
        //没按下虚拟摇杆：
        if (!isAnyVirtualAxisDown)
        {
            //尝试获得WASD移动方向：
            GetHorizontalAxis();
            GetVerticalAxis();
        }
#endif
        return axisVector;
    }

    [System.Obsolete()]
    /// <summary>
    /// 释放所有可按下的功能键
    /// </summary>
    public static void ReleaseFunctionKeys()
    {
        //释放所有锁定（直到获取时才被重置）的bool键：
        isJumpButtonDown = false;
        isAttackButtonDown = false;
        isThrowButtonDown = false;
    }

    /// <summary>
    /// 重置摇杆数据
    /// </summary>
    public static void ResetAxis()
    {
        axisVector = Vector2.zero;
    }


    /// <summary>
    /// 设置MyInput Canvas（需已经实例化）下的对应按钮及其功能
    /// </summary>
    /// <param name="buttonName">对应按钮名称</param>
    /// <param name="onButtonClick">点击时发生的事件</param>
    public static void SetButtonFunction(string buttonName, CallbackFunc onButtonClick)
    {
        SetButtonFunction(buttonName, onButtonClick, null, null);
    }

    /// <summary>
    /// 设置MyInput Canvas（需已经实例化）下的对应按钮及其功能
    /// </summary>
    /// <param name="buttonName">对应按钮名称</param>
    /// <param name="onButtonDown">当按钮按下时的触发事件</param>
    /// <param name="onButtonUp">当按钮释放的事件</param>
    public static void SetButtonFunction(string buttonName, CallbackFunc onButtonDown, CallbackFunc onButtonUp)
    {
        SetButtonFunction(buttonName, null, onButtonDown, onButtonUp);
    }

    /// <summary>
    /// 设置MyInput Canvas（需已经实例化）下的对应按钮及其功能
    /// </summary>
    /// <param name="buttonName">对应按钮名称</param>
    /// <param name="onButtonClick">点击时发生的事件</param>
    /// <param name="onButtonDown">当按钮按下时的触发事件</param>
    /// <param name="onButtonUp">当按钮释放的事件</param>
    public static void SetButtonFunction(string buttonName, CallbackFunc onButtonClick, CallbackFunc onButtonDown, CallbackFunc onButtonUp)
    {
        if (g_instance == null)
        {
            Debug.LogWarning("No MyInput instance.");
            return;
        }
        var canvas = g_instance.GetComponentInParent<Canvas>();
        if (canvas == null)
        {
            Debug.LogWarning("No canvas set or it is hidden.");
            return;
        }

        Transform canvasTrans = canvas.transform;

        //获得按钮
        var btnTrans = canvasTrans.GetChildByName(buttonName);
        if (btnTrans == null)
        {
            Debug.LogWarning("Cannot find button[" + buttonName + "] in " + canvasTrans.name + " to bind the function.");
            return;
        }


        SetButtonFunction(btnTrans, onButtonClick, onButtonDown, onButtonUp);
    }

    public static void SetButtonFunction(Transform btnTrans, CallbackFunc onButtonClick, CallbackFunc onButtonDown, CallbackFunc onButtonUp)
    {
        if (btnTrans == null)
        {
            Debug.LogWarning("Cannot bind a null button with function.");
            return;
        }

        var btn = btnTrans.GetComponent<GameUIClickable>();
        if (btn == null)
        {
            btn = btnTrans.gameObject.AddComponent<GameUIClickable>();
        }

        //--添加对应的行为回调
        btn.SetOnClickListener(onButtonClick, onButtonDown, onButtonUp);
    }

    #region 不推荐使用的仿GetKey、GetKeyDown，方法在PC | 移动端（需要有对应Canvas和调用AwakeButton）有效
    static bool[] m_isKeysDown = new bool[14];           //是否按下，默认最多14键
    static bool[] m_isKeysOn = new bool[14];               //是否按住，默认最多14键
    static bool[] m_isKeysFreeze = new bool[14];
    static bool m_clearKeysAfterFrame; //是否有任一按键按下，是的话将在帧结束后清除标记
    static Dictionary<int, KeyCode> m_customToPCKeyCode = null;

    /// <summary>
    /// 批量设置枚举之中的所有KeyCode对应的按钮功能，按下时可以通过GetButtonDown访问（会清除其他类设置的按键）
    /// <para>注意：必须存在MyInput所属的Canvas，且按键在Canvas之中，且按键的Button名称与之相同</para>
    /// </summary>
    /// <typeparam name="T">需要的KeyCode枚举</typeparam>
    /// <param name="enumCount">如果有Count的枚举，则填入其值，并跳过该按钮及其以后的设置</param>
    public static void InitKeyCodeFunction<T>(int enumCount = -1) where T : struct, IConvertible
    {
        InitKeyCodeFunction<T>(new Dictionary<string, string>(), enumCount);
    }


    /// <summary>
    /// 批量设置MyInput的画布中，按枚举指定的所有按钮功能，按下时可以通过GetButtonDown访问（会清除其他类设置的按键）
    /// <para>注意：必须存在MyInput所属的Canvas，且按键在Canvas之中</para>
    /// </summary>
    /// <param name="keyCodeToBtnNameDict">额外指定 KeyCode键-映射到按钮上的名称，则会将该按钮视作某个KeyCode</param>
    /// <typeparam name="T">需要的KeyCode枚举</typeparam>
    /// <param name="enumCount">如果有Count的枚举，则填入其值，跳过该按钮及其以后的设置</param>
    public static void InitKeyCodeFunction<T>(Dictionary<string, string> keyCodeToBtnNameDict, int enumCount = -1) where T : struct, IConvertible
    {
        InitKeyCodeFunction<T>(null, keyCodeToBtnNameDict, enumCount);
    }

    /// <summary>
    /// 批量设置枚举之中的所有按钮功能，按下时可以通过GetButtonDown访问（会清除其他类设置的按键）
    /// <para>不要求按键在Input所属的Canvas中</para>
    /// </summary>
    /// <param name="keyCodeToBtnDict">额外指定 KeyCode键-映射到按钮上的名称，则会将该按钮视作某个KeyCode</param>
    /// <typeparam name="T">需要的KeyCode枚举</typeparam>
    /// <param name="enumCount">如果有Count的枚举，则填入其值，跳过该按钮及其以后的设置</param>
    public static void InitKeyCodeFunction<T>(Dictionary<string, RectTransform> keyCodeToBtnDict, int enumCount = -1) where T : struct, IConvertible
    {
        InitKeyCodeFunction<T>(keyCodeToBtnDict, null, enumCount);
    }
    /// <summary>
    /// 批量设置枚举之中的所有按钮功能，按下时可以通过GetButtonDown访问（会清除其他类设置的按键）
    /// <para>注意：必须存在MyInput所属的Canvas，且按键在Canvas之中</para>
    /// </summary>
    /// <param name="keyCodeToBtnNameDict">额外指定 KeyCode键-映射到按钮上的名称，则会将该按钮视作某个KeyCode</param>
    /// <typeparam name="T">需要的KeyCode枚举</typeparam>
    /// <param name="enumCount">如果有Count的枚举，则填入其值，跳过该按钮及其以后的设置</param>
    private static void InitKeyCodeFunction<T>(Dictionary<string, RectTransform> keyCodeToBtnDict, Dictionary<string, string> keyCodeToBtnNameDict, int enumCount = -1) where T : struct, IConvertible
    {
        //Get Enums:
        Array keyEnums = Enum.GetValues(typeof(T));

        //Generate booleans
        int keyCodesCount = enumCount > 0 ? enumCount : keyEnums.Length;
        m_isKeysDown = new bool[keyCodesCount];
        m_isKeysOn = new bool[keyCodesCount];
        m_isKeysFreeze = new bool[keyCodesCount];

        bool hasKeyCodeToNameDict = GameObjFunc.HasItems(keyCodeToBtnNameDict);
        bool hasKeyCodeToBtnDict = GameObjFunc.HasItems(keyCodeToBtnDict);
        foreach (var keyCodeInfo in keyEnums)
        {
            int keyCodeIndex = (int)keyCodeInfo;

            if (enumCount > 0)
            {
                //Skip the COUNT Enum if exist
                if (keyCodeIndex >= enumCount)
                {
                    continue;
                }
            }

            //Find the key button & set the function
            string keyButtonName = keyCodeInfo.ToString();
            if (hasKeyCodeToNameDict && keyCodeToBtnNameDict.ContainsKey(keyButtonName))
            {
                //指定名称的情况：指定了某个按键对应的按钮名称，则使用映射的按钮名称：
                ReBindButtonToKeyCode(keyCodeToBtnNameDict[keyButtonName], keyCodeIndex);
            }
            else if (!hasKeyCodeToNameDict && keyCodeToBtnDict.ContainsKey(keyButtonName))
            {
                //直接绑定按键，而不是指定名称：
                ReBindButtonToKeyCode(keyCodeToBtnDict[keyButtonName], keyCodeIndex); ;
            }
            else
            {
                //默认则绑定KeyCode指定的按钮名称：
                ReBindButtonToKeyCode(keyButtonName, keyCodeIndex);
            }

        }
    }

    /// <summary>
    /// 直接指定自定义的KeyCode与PC键盘的KeyCode关系（不一定需要KeyCode相同）
    /// </summary>
    /// <param name="keyCodeToCustomKeyCodes">Key code to custom key codes.</param>
    public static void BindPCKeyCodeToCustomKeyCode(Dictionary<KeyCode, Enum> keyCodeToCustomKeyCodes)
    {
        if (GameObjFunc.HasItems(keyCodeToCustomKeyCodes))
        {
            if (m_customToPCKeyCode == null)
            {
                m_customToPCKeyCode = new Dictionary<int, KeyCode>();
            }
            foreach (var pcToCustomKeyIndexer in keyCodeToCustomKeyCodes)
            {
                int customKeyValue = Convert.ToInt32(pcToCustomKeyIndexer.Value);

                m_customToPCKeyCode[customKeyValue] = pcToCustomKeyIndexer.Key;
            }
        }
    }

    /// <summary>
    /// 重设MyInput 的Canvas中的某个button对应的keycode 及其回调
    /// </summary>
    /// <param name="keyButtonName">Key button name.</param>
    /// <param name="keyCodeIndex">Key code index.</param>
    /// <param name="onKeyDown">On key down.</param>
    /// <param name="onKeyUp">On key up.</param>
    public static void ReBindButtonToKeyCode(string keyButtonName, int keyCodeIndex, CallbackFunc onKeyDown = null, CallbackFunc onKeyUp = null)
    {
        ReBindButtonToKeyCode(null, keyButtonName, keyCodeIndex, onKeyDown, onKeyUp);
    }

    /// <summary>
    /// 重设某个button对应的keycode 及其回调
    /// </summary>
    /// <param name="keyButtonTrans">Key button transform.</param>
    /// <param name="keyCodeIndex">Key code index.</param>
    /// <param name="onKeyDown">On key down.</param>
    /// <param name="onKeyUp">On key up.</param>
    public static void ReBindButtonToKeyCode(RectTransform keyButtonTrans, int keyCodeIndex, CallbackFunc onKeyDown = null, CallbackFunc onKeyUp = null)
    {
        ReBindButtonToKeyCode(keyButtonTrans, null, keyCodeIndex, onKeyDown, onKeyUp);
    }

    /// <summary>
    /// 重设某个button对应的keycode 及其回调
    /// </summary>
    /// <param name="keyButtonTrans">Key button Trans.</param>
    /// <param name="keyButtonName">Button name</param>
    /// <param name="keyCodeIndex">Key code index.</param>
    /// <param name="onKeyDown">On key down.</param>
    /// <param name="onKeyUp">On key up.</param>
    private static void ReBindButtonToKeyCode(RectTransform keyButtonTrans, string keyButtonName, int keyCodeIndex, CallbackFunc onKeyDown = null, CallbackFunc onKeyUp = null)
    {

#if UNITY_EDITOR
        if (keyCodeIndex > m_isKeysDown.Length)
        {
            throw new NotImplementedException("Use Enums that defined by yourself instead,Current keycode value:" + keyCodeIndex);
        }
#endif
        //创建回调：
        CallbackFunc onDown =
            () =>
            {
                m_isKeysDown[keyCodeIndex] = true;
                m_isKeysOn[keyCodeIndex] = true;

                //标记在帧结束后，需要做好清除Down标记工作：
                m_clearKeysAfterFrame = true;

                if (onKeyDown != null)
                {
                    onKeyDown();
                }

            };

        CallbackFunc onUp = () =>
         {
             m_isKeysDown[keyCodeIndex] = false;
             m_isKeysOn[keyCodeIndex] = false;

             if (onKeyUp != null)
             {
                 onKeyUp();
             }

         };

        //绑定事件
        //--是指定RectTransform的：
        if (keyButtonTrans != null)
        {
            SetButtonFunction(keyButtonTrans, null, onDown, onUp);
        }
        else
        {
            //否则是指定Button名称的：
            SetButtonFunction(keyButtonName, null, onDown, onUp);
        }
    }

    /// <summary>
    /// 锁定/解锁某个按键，使之按下无效
    /// </summary>
    /// <param name="selfKeyCodeEnum">Self key code enum.</param>
    /// <param name="isLock">是否锁定该按键</param>
    public static void SetButtonLock(Enum selfKeyCodeEnum,bool isLock)
    {
        m_isKeysFreeze[Convert.ToInt32(selfKeyCodeEnum)] = isLock;
    }

    /// <summary>
    /// 按键按下？（注意：不要使用KeyCode，而使用自定义的Code。且必须场景中存在MyInput所属的Canvas并执行Awake以唤醒按钮功能）
    /// </summary>
    /// <param name="selfDefinedKeyCode">自行定义的KeyCode，不要使用KeyCode</param>
    /// <returns></returns>
    public static bool GetButtonDown(Enum selfDefinedKeyCode)
    {
#if UNITY_EDITOR
        if (selfDefinedKeyCode is KeyCode)
        {
            throw new NotImplementedException("Use Enums that defined by yourself instead");
        }
#endif

        int keyIndex = Convert.ToInt32(selfDefinedKeyCode);
        //Console.WriteLine("Key index:" + keyIndex);

        if (m_isKeysDown[keyIndex]
            && !m_isKeysFreeze[keyIndex])
        {
            return true;
        }

#if UNITY_EDITOR || UNITY_STANDALONE
        return TryGetPCKey(selfDefinedKeyCode, false);
#endif
        return false;
    }

    /// <summary>
    /// Is button Pressing? （注意：必须场景中存在MyInput所属的Canvas并执行Awake以唤醒按钮功能）
    /// </summary>
    /// <param name="keyCode"></param>
    /// <returns></returns>
    public static bool GetButton(Enum keyCode)
    {
        int keyIndex = Convert.ToInt32(keyCode);

        if (m_isKeysOn[keyIndex]
            && !m_isKeysFreeze[keyIndex])
        {
            return true;
        }

#if UNITY_EDITOR || UNITY_STANDALONE
        TryGetPCKey(keyCode, true);
#endif

        return false;
    }

    /// <summary>
    /// 尝试从自定义的按键，指定为PC键盘的输入
    /// </summary>
    /// <returns><c>true</c>, if get PCK ey was tryed, <c>false</c> otherwise.</returns>
    /// <param name="selfDefinedKeyCode">Self defined key code.</param>
    /// <param name="isHolding">If set to <c>true</c> is holding.</param>
    private static bool TryGetPCKey(Enum selfDefinedKeyCode, bool isHolding)
    {
        int keyIndex = Convert.ToInt32(selfDefinedKeyCode);
        if(m_isKeysFreeze[keyIndex])
        {
            return false;
        }

        bool gotKey = false;
        KeyCode pcKey;
        if (TryParse<KeyCode>(selfDefinedKeyCode.ToString(), out pcKey))
        {
            gotKey = true;
        }
        else
        {
            if (GameObjFunc.HasItems(m_customToPCKeyCode))
            {
                int custKeyVal = Convert.ToInt32(selfDefinedKeyCode);
                if (m_customToPCKeyCode.TryGetValue(custKeyVal, out pcKey))
                {
                    gotKey = true;
                }
            }
        }

        if (gotKey)
        {
            if (isHolding)
            {
                return Input.GetKey(pcKey);
            }
            else
            {
                return Input.GetKeyDown(pcKey);
            }
        }
        return false;
    }



    /// <summary>
    /// 帧结束后清除KeyDown标记
    /// </summary>
    private void ClearKeysFlag()
    {
        for (int i = 0; i < m_isKeysDown.Length; i++)
        {
            m_isKeysDown[i] = false;
        }
    }


    /// <summary>
    /// 尝试转换Enum，2.0的mscorlib似乎缺少此方法，补之
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="strEnumCode"></param>
    /// <returns></returns>
    private static bool TryParse<T>(string strEnumCode, out T enumCode)
    {
        object pcKeyCode = null;
        try
        {
            pcKeyCode = Enum.Parse(typeof(KeyCode), strEnumCode);
        }
        catch
        {
            pcKeyCode = null;
        }

        enumCode = default(T);
        if (pcKeyCode != null)
        {
            enumCode = (T)pcKeyCode;
            return true;
        }
        else
        {
            return false;
        }
    }
    #endregion

    #region PC Only

#if UNITY_STANDALONE || UNITY_EDITOR
    /// <summary>
    /// 常见的游戏按钮
    /// </summary>
    public enum GameKey
    {
        /// <summary>
        /// 水平方向
        /// </summary>
        Horizontal,

        /// <summary>
        /// 竖直方向
        /// </summary>
        Vertical,

        /// <summary>
        /// 跳
        /// </summary>
        Jump,

        /// <summary>
        /// 攻击
        /// </summary>
        Attack,

        /// <summary>
        /// 攻击2
        /// </summary>
        Attack2,

        /// <summary>
        /// 攻击3
        /// </summary>
        Attack3,

        /// <summary>
        /// 加速跑
        /// </summary>
        Trot,

        /// <summary>
        /// 互动
        /// </summary>
        Interact,
    }

    /// <summary>
    /// PC Only：Unity预制按键是否正按住
    /// </summary>
    /// <param name="gameKey"></param>
    /// <returns></returns>
    public static bool PCGetButton(GameKey gameKey)
    {
        return Input.GetButton(gameKey.ToString());
    }

    /// <summary>
    /// Unity预制按键是否Down
    /// </summary>
    /// <param name="gameKey"></param>
    /// <returns></returns>
    public static bool PCGetButtonDown(GameKey gameKey)
    {
        return Input.GetButtonDown(gameKey.ToString());
    }

    /// <summary>
    /// Unity预制按键是否Up
    /// </summary>
    /// <param name="gameKey"></param>
    /// <returns></returns>
    public static bool PCGetButtonUp(GameKey gameKey)
    {
        return Input.GetButtonUp(gameKey.ToString());
    }

#endif
    #endregion

    /// <summary>
    /// 获得MyInput所在的Canvas下指定UI物体组件
    /// </summary>
    /// <typeparam name="T">UI物体组件</typeparam>
    /// <param name="uiName">该组件名</param>
    /// <returns></returns>
    public static T GetUIObject<T>(string uiName)
    {
        return g_instance.GetComponentInParent<Canvas>()
                .transform.GetChildByName<T>(uiName);
    }

    #endregion

    #region --鼠标或者Touch输入
    //--预判用--：#if UNITY_EDITOR || UNITY_STANDALONE

    public static int touchCount
    {
        get
        {
#if UNITY_EDITOR || UNITY_STANDALONE
            return GetMouse() ? 1 : 0;//唯有1与0
#else
            return Input.touchCount;
#endif
        }
    }

    /// <summary>
    /// 触摸或鼠标左键正在按住
    /// </summary>
    public static bool GetMouse(int pcMouseId = 0)
    {
#if UNITY_EDITOR || UNITY_STANDALONE
        return Input.GetMouseButton(pcMouseId);

#else
        return Input.touchCount > 0;
#endif
    }

    /// <summary>
    /// 触摸或鼠标按下。（默认鼠标判断左键）
    /// </summary>
    /// <param name="pcMouseId">0=左键，1=右键，2=中键.仅对PC有效，对于触控时无参数影响</param>
    public static bool GetMouseDown(int pcMouseId = 0)
    {
#if UNITY_EDITOR || UNITY_STANDALONE
        return Input.GetMouseButtonDown(pcMouseId);
#else

        if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
        {
            return true;
        }
        return false;
#endif


    }

    /// <summary>
    /// 触摸或鼠标按下
    /// </summary>
    /// <param name="pcMouseId">0=左键，1=右键，2=中键.对于触控时无参数影响</param>
    public static bool GetMouseUp(int pcMouseId = 0)
    {
#if UNITY_EDITOR || UNITY_STANDALONE
        return Input.GetMouseButtonUp(pcMouseId);

#else

        if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Ended)
        {
            return true;
        }
        return false;
#endif
    }

    static Vector2 mouseClickPos;
    static bool hasClickedDown = false;
    /// <summary>
    /// 查看是否发生了单击行为（在同一个点按下和释放鼠标/触摸）
    /// </summary>
    public static bool GetMouseClick(int pcMouseId = 0)
    {
        //还未点击，现在点击了
        if (!hasClickedDown)
        {
            if (GetMouseDown(pcMouseId))
            {
                hasClickedDown = true;
                mouseClickPos = mousePosition;
            }
        }
        else//ClickDowned，now try to get up 
        if (GetMouseUp(pcMouseId))
        {
            //--前后差距足够小，即为在该点点击
            Vector2 currPos = mousePosition;
            if (Vector2.SqrMagnitude(currPos - mouseClickPos) < 1)
            {
                return true;
            }

            hasClickedDown = false;
        }

        return false;
    }

    static float lastClickTime = -1;
    /// <summary>
    /// 查看是否发生了第二次点击后的长按行为（在同一个点两次按下后不释放鼠标）
    /// </summary>
    public static bool GetMouseDoubleHold(int pcMouseId = 0)
    {
        //第一次的按下
        if (GetMouseClick(pcMouseId))
        {
            lastClickTime = Time.time;
            return false;
        }
        //如果是第二次按下（需要综合上次点击时间考虑）
        else if (GetMouseDown(pcMouseId)
        && Time.time - lastClickTime < 0.3f)
        {
            Debug.Log("DDDDD");
            lastClickTime = -1;
            return true;
        }

        return false;
    }

    /// <summary>
    /// 判断是否在UI上，但是反之不定在游戏物体上；
    /// </summary>
    /// <returns></returns>
    public static bool IsMouseOnUI()
    {
#if UNITY_EDITOR
        if (EventSystem.current == null)
        {
            Debug.LogError("No eventSystem found.");
            return false;
        }
#endif

        if (
#if UNITY_STANDALONE || UNITY_EDITOR
EventSystem.current.IsPointerOverGameObject() == false//false即为在物体上而非UI上
#else
            Input.touchCount==1
            && EventSystem.current.IsPointerOverGameObject(0) == false//false即为在物体上而非UI上
#endif
            )
        {
            //并不在UI上
            return false;
        }
        else
        {
            return true;
        }
    }

    [System.Obsolete("USE IsMouseOnObj() instead.")]
    /// <summary>
    /// 获得在鼠标位置的obj，弃用
    /// </summary>
    /// <seealso cref="IsMouseOnObj"/>
    public static bool GetObjOnMouse(out Transform obj)
    {
        return IsMouseOnObj(out obj);
    }

    /// <summary>
    /// 获得鼠标/触摸（不指定是否按下） 当前所指向的物体
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static bool IsMouseOnObj(out Transform obj)
    {
        RaycastHit hit;
        if (IsMouseOnObj(out hit))
        {
            obj = hit.transform;
            return true;
        }
        else
        {
            obj = null;
            return false;
        }
    }



    /// <summary>
    /// 判断当前鼠标（不指定是否按下）是否在游戏物体上。无则为Null， 否则返回碰撞消息
    /// </summary>
    public static bool IsMouseOnObj(out RaycastHit hit)
    {
        //         if (
        // #if UNITY_STANDALONE || UNITY_EDITOR
        // EventSystem.current.IsPointerOverGameObject() == false//false即为非UI
        // #else
        //             Input.touchCount==1
        //             && EventSystem.current.IsPointerOverGameObject(0) == false//false即为非UI
        // #endif
        //             )
        // {
        Camera cam = Camera.main;
        Ray ray = cam.ScreenPointToRay(mousePosition);
        //直接返回是否在物体上，以及对应的碰撞信息
        return (Physics.Raycast(ray, out hit));
        // }
        // else
        // {

        //     //在ui上：
        //     return false;
        // }
    }

    /// <summary>
    /// 获得触摸或鼠标位置
    /// </summary>
    public static Vector3 mousePosition
    {
        get
        {
#if UNITY_EDITOR || UNITY_STANDALONE
            return Input.mousePosition;
#else
                if (Input.touchCount > 0)
                    return Input.GetTouch(0).position;
                else return Vector3.zero;
#endif
        }
    }

    #region 移动端缩放/移动空白地方操作的静态函数

    static float m_moveViewSpeed = 600F;
    static Vector2 currTouchPos = Vector2.zero;                        //当前触摸/鼠标的位置
    static Vector2 lastTouchPos = Vector2.zero;                        //上一次鼠标/触摸的位置
    static Vector2 secTouchLastTouchPos = Vector2.zero;        //第二根手指头的上一轮的位置

    /// <summary>
    /// PC Only:是否移动了视图（PC：鼠标右键/中键移动），返回时间间隔内偏移值。
    /// （直接使用GetMouseDragDelta）
    /// <para>PS：必须在Update中被调用，才能获得移动偏移值</para>
    /// </summary>
    /// <param name="moveViewDelta">前后移动的差值</param>
    /// <param name="minDelta">最小偏移值，避免抖动</param>
    /// <returns>是否移动了</returns>
    public static bool IsMouseDragDelta(out Vector2 moveViewDelta, float minDelta = 1)
    {
        return GetMouseDragDelta(out moveViewDelta, minDelta);
    }

    /// <summary>
    /// Mouse或Touch是否拖动了，返回时间间隔内偏移值（大于阙值）。
    /// <para>PS：必须在Update中被调用，才能获得移动偏移值</para>
    /// </summary>
    /// <param name="dragDelta">前后移动的差值</param>
    /// <param name="minDelta">最小偏移值，避免抖动</param>
    /// <param name="mouseId">检查的鼠标/触控ID</param>
    /// <returns>是否移动了</returns>
    public static bool GetMouseDragDelta(out Vector2 dragDelta, float minDelta = 1, int mouseId = 0)
    {
        dragDelta = Vector2.zero;

        //第一次的按下
        if (GetMouseDown(mouseId))
        {
            lastTouchPos = MyInput.mousePosition;

            //返回无位置移动
            return false;
        }
        else if (GetMouse(mouseId))                //按下且拖拽
        {

            //获得距离差：
            Vector2 mousePos = MyInput.mousePosition;
            dragDelta = lastTouchPos - mousePos;

            if (dragDelta.SqrMagnitude() > minDelta)                                //达到预定范围，则取此偏移值并返回
            {
                //接受此次的距离差
                lastTouchPos = mousePos;

                return true;
            }
        }
        return false;
    }

    //#if MOBILE_INPUT
    private static bool beginDragScale = false;                                //用于标记第一帧开始控制时
    private static float lastTouchDistance = 0;                                        //上一帧间的拖拽距离
    private static float distanceNoiseDelta = 64;                                      //距离噪点64pixel以内，拒绝抖动
    private static bool m_acceptControll = false;                                  //是否接受控制
    /// <summary>
    /// 提供判断触摸屏两指缩放操作：返回为是否有两指拖拽操作
    /// </summary>
    /// <param name="scaleFactor">两指拖拽的距离差</param>
    /// <returns>是否有两指拖拽操作</returns>
    public static bool HasScrollViewOp(out float scaleFactor)
    {
        scaleFactor = 0;

#if UNITY_STANDALONE || UNITY_EDITOR
        if (EventSystem.current.IsPointerOverGameObject() == false)
        {
            //PC时，通过滚轮取得缩放值
            scaleFactor = Input.mouseScrollDelta.y * 3;
            return Mathf.Abs(scaleFactor) > 0.1F;
        }
        else
        {
            return false;
        }
#elif MOBILE_INPUT
//Mobile时，通过两根手指间的缩放距离取得缩放：
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
    //开始按下的刹那
    if (EventSystem.current.IsPointerOverGameObject(0) == false)
    {
        //若是指尖触及
        m_acceptControll = true;                                //Not UI
    }
    else
    {
        //还是彷徨
        m_acceptControll = false;                               //Touching UI
        return false;
    }
}


if (m_acceptControll && Input.touchCount >= 2)
{
        #region 指间拖拽了那时轻狂

    if (!beginDragScale)
    {
        //The first status: Record the touches
        lastTouchDistance = Vector2.Distance(
                Input.GetTouch(0).position, Input.GetTouch(1).position);        //Sqrt of Magnitude

        beginDragScale = true;
    }
    else
    {
        //Draging...This is Next Frame:
        float currDistance = Vector2.Distance(
                Input.GetTouch(0).position, Input.GetTouch(1).position);         //Sqrt of Magnitude

        float delta = currDistance - lastTouchDistance;
        if (Mathf.Abs(delta) > distanceNoiseDelta)
        {
            //Accept change:
            scaleFactor = delta*0.1F;

            //Recaculate next.
            lastTouchDistance = currDistance;

            return true;
        }

    }
        #endregion
}
else
{
    //却放纵了韶华
    beginDragScale = false;
}

return false;
#endif
    }

    //#endif
    #endregion

    #endregion

    #endregion

    //--------------------------------------------------------------------------------------------------------------
    //                                          实例操作部分
    //  
    //--------------------------------------------------------------------------------------------------------------
    #region --虚拟摇杆用数据--
    //--虚拟按键中的ID配置用
    [SerializeField] string m_btnJumpName = "JumpButton";            //跳跃键在Canvas中的序号
    [SerializeField] string m_btnAttackName = "AttackButton";            //攻击键在Canvas中的序号
    [SerializeField] string m_btnThrowName = "E_Button";            //投掷键(额外功能键)在Canvas中的序号
    [SerializeField] bool m_disableInputPadOnPC = false;                     //在PC上运行时是否隐藏MyInput的虚拟按键

    //--虚拟摇杆用
    static Vector2 axisVector;
    //--任何虚拟摇杆中的按键按下了：
    static bool isAnyVirtualAxisDown;
    static bool isJumpButtonDown;
    static bool isThrowButtonDown;
    static bool isAttackButtonDown;

    static MyInput g_instance;

    public enum AxisOption
    {
        // Options for which axes to use
        Both, // Use both
        OnlyHorizontal, // Only horizontal
        OnlyVertical // Only vertical
    }

    public AxisOption axesToUse = AxisOption.Both;                    // The options for the axes that the still will use
    RectTransform moveRangeParent;
    int MoveRadiusRange = 100;                                                    //The radius of movement range.

    Vector2 m_StartAnchoredPos;
    Vector2 m_StartDragPos;
    bool m_UseX = true;                                                                // Toggle for using the x axis
    bool m_UseY = true;                                                                // Toggle for using the Y axis

    RectTransform m_rectTransform;

    #endregion

    void Awake()
    {
        //将EventSystem的部分放到Start时点进行检查：
        StartCoroutine(GameObjFunc.IDelayDoSth(() =>
        {
            if (EventSystem.current == null)
            {
                Debug.LogWarning("NO EventSystem was found in current scene. I will create one that will be destroyed after playing.");
                this.gameObject.AddComponent<EventSystem>();
            }
        }));

        g_instance = this;

        m_rectTransform = GetComponent<RectTransform>();
        m_StartAnchoredPos = m_rectTransform.anchoredPosition;
        moveRangeParent = m_rectTransform.parent.GetComponent<RectTransform>();

        //计算可移动半径范围：
        //--内圆Radius：
        float stickRadius = m_rectTransform.rect.width * 0.5F;
        //--外圆Radius：
        float moveRadius = moveRangeParent.rect.width * 0.5F;
        //--可移动范围
        MoveRadiusRange = (int)(moveRadius - stickRadius);

        Transform canvasTrans = GetComponentInParent<Canvas>().transform;

        //如果无需显示，则在非移动的情况下关闭
        if (m_disableInputPadOnPC && Application.isMobilePlatform == false)
        {
            canvasTrans.gameObject.SetActive(false);
            return;
        }

        //获得按钮
        Button btn = canvasTrans.GetChildByName<Button>(m_btnJumpName);
        if (btn)
        {
            //注册跳JumpButton：
            btn.onClick.AddListener(() =>
            {
                isJumpButtonDown = true;
            });
        }

        btn = canvasTrans.GetChildByName<Button>(m_btnThrowName);
        if (btn)
        {
            //注册投掷互动ButtonE
            btn.onClick.AddListener(() =>
            {
                isThrowButtonDown = true;
            });
        }

        btn = canvasTrans.GetChildByName<Button>(m_btnAttackName);
        if (btn)
        {
            //注册攻击按钮Attack
            btn.onClick.AddListener(() =>
            {
                isAttackButtonDown = true;
            });
        }

    }

    void LateUpdate()
    {
        if (m_clearKeysAfterFrame)
        {
            ClearKeysFlag();
        }
    }


    void OnDisable()
    {
        //释放方向键
        this.OnPointerUp(null);
    }

    /// <summary>
    /// 传输更新虚拟轴数据到输入管理中
    /// </summary>
    void UpdateVirtualAxes(Vector2 value)
    {
        axisVector = m_StartAnchoredPos - value;
        //Debug.Log("delta:" + delta);
        axisVector.y = -axisVector.y;
        axisVector /= MoveRadiusRange;
        if (m_UseX)
        {
            axisVector.x = -axisVector.x;
        }
    }


    //继承函数：Drag时触发
    public void OnDrag(PointerEventData data)
    {

        //标记有移动；
        isAnyVirtualAxisDown = true;

        //新计算方法：
        //获得移动差值
        Vector2 posDelta = data.position - m_StartDragPos;

        //如果不是双向可移动，去掉特定轴
        if (!m_UseX) posDelta.x = 0;
        if (!m_UseY) posDelta.y = 0;

        //差值限制，利用等比三角形：差值过大时，外直角边与目标直角边成比例；
        float r1 = MoveRadiusRange;
        if (Vector2.SqrMagnitude(posDelta) > r1 * r1)
        {
            //--首先去掉0值、近似0情况：
            float absX = Mathf.Abs(posDelta.x);
            float absY = Mathf.Abs(posDelta.y);

            if (absX < 0.01F)
            {
                posDelta.x = 0;
                posDelta.y = r1 * (posDelta.y > 0 ? 1 : -1);
            }
            else if (absY < 0.01F)
            {
                posDelta.x = r1 * (posDelta.x > 0 ? 1 : -1);
                posDelta.y = 0;
            }
            else
            {
                //三角形趋于X边比值较重（超出r的情况
                float rPos = posDelta.magnitude;
                //--使用等比三角的公式：x?/xPos=r1/rPos
                posDelta.x = r1 / rPos * posDelta.x;
                posDelta.y = r1 / rPos * posDelta.y;

            }
        }

        Vector2 newPos = m_StartAnchoredPos + posDelta;
        //否则予以移动：
        //--更新移动视图
        m_rectTransform.anchoredPosition = newPos;

        //更新轴数据：
        UpdateVirtualAxes(m_rectTransform.anchoredPosition);
    }


    public void OnPointerUp(PointerEventData data)
    {
        //标记移动虚拟轴结束：
        isAnyVirtualAxisDown = false;

        m_rectTransform.anchoredPosition = m_StartAnchoredPos;
        UpdateVirtualAxes(m_StartAnchoredPos);
    }


    public void OnPointerDown(PointerEventData data)
    {
        isAnyVirtualAxisDown = true;
        //开始拖拽时记录鼠标位置
        m_StartDragPos = data.position;
    }


}

